/*-----------------------------------------------------------------------------------------------*/
	
	function AbductionCapture(content) {
		var self = AbductionCapture;
		
		self.content = content;
		self.prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
		window.onunload = self.cleanup;
		
		// Choose the best filename:
		if (content.document.title) {
			self.filename = content.document.title;
		} else {
			self.filename = content.document.URL;
		}
		
		// Set window title:
		document.title = self.filename + " - " + document.title;
		
		// Find settings:
		self.settings = {
			"colour": self.prefs.getCharPref("abduction.capture.color"),
			"opacity": self.prefs.getCharPref("abduction.capture.opacity"),
			"format": self.prefs.getIntPref("abduction.capture.format")
		};
		
		// Find areas:
		self.areas = {
			"stack": document.getElementById("stack"),
			"canvas": document.getElementById("canvas"),
			"overlay": document.getElementById("overlay"),
			"border": document.getElementById("border"),
			"surface": document.getElementById("surface"),
			"base": document.getElementById("base"),
			"scroll": document.getElementById("base").boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject)
		};
		
		// Find buttons:
		self.buttons = {
			"reset": document.getElementById("reset"),
			"print": document.getElementById("print"),
			"copy": document.getElementById("copy"),
			"save": document.getElementById("save"),
			"close": document.getElementById("close")
		};
		
		// Find inputs:
		self.inputs = {
			"colour": document.getElementById("colour"),
			"picker": document.getElementById("picker"),
			"opacity": document.getElementById("opacity"),
			"format": document.getElementById("format"),
			"mode": document.getElementById("mode")
		}
		
		// Prepare states:
		self.select = {
			"top": 0, "left": 0, "height": 0, "width": 0, "active": false
		};
		
		// Prepare areas:
		self.areas.surface.onmousedown = self.overlayStart;
		self.areas.surface.onmousemove = self.overlayDrag;
		self.areas.surface.onmouseup = self.overlayStop;
		
		// Prepare buttons:
		self.buttons.reset.onclick = self.reset;
		self.buttons.print.onclick = self.print;
		self.buttons.print.hidden = true;
		self.buttons.copy.onclick = self.copy;
		self.buttons.copy.hidden = true;
		self.buttons.save.onclick = self.save;
		self.buttons.close.onclick = function() { window.close(); };
		
		// Prepare inputs:
		self.inputs.colour.value = self.settings.colour;
		self.inputs.colour.onchange = self.overlayDraw;
		self.inputs.picker.onchange = function() {
			self.inputs.colour.value = self.inputs.picker.color.toLowerCase();
			self.inputs.colour.onchange();
		};
		self.inputs.opacity.value = self.settings.opacity * 100;
		self.inputs.opacity.onchange = self.overlayDraw;
		self.inputs.format.value = self.settings.format;
		self.inputs.format.onselect = function() {
			self.prefs.setIntPref("abduction.capture.format", self.inputs.format.value);
		}
		
		// Start drawing:
		self.canvasDraw();
		self.overlayDraw();
	}
	
	// Draw source to canvas:
	AbductionCapture.canvasDraw = function() {
		var self = AbductionCapture;
		var context = self.areas.canvas.getContext('2d');
		var root = null, body = null;
		var height = 0, width = 0;
		
		// This should always work:
		if ((root = self.content.document.documentElement)) {
			height = root.offsetHeight | root.scrollHeight;
			width = root.offsetWidth | root.scrollWidth;
		}
		
		// Sometimes only body has correct values:
		if (!height && (body = self.content.document.body)) {
			height = height | body.offsetHeight | body.scrollHeight;
		}
		
		// Set area size:
		self.areas.canvas.height = self.areas.overlay.height = height;
		self.areas.canvas.width = self.areas.overlay.width = width;
		self.areas.surface.style.height = height + "px";
		self.areas.surface.style.width = width + "px";
		
		// Prepare selection:
		self.select.height = height;
		self.select.width = width;
		
		// Draw the canvas:
		try {
			context.drawWindow(self.content, 0, 0, width, height, "rgb(255,255,255)");
			
		} catch (error) {
			window.close();
			alert(error);
		}
	}
	
	// Draw overlay:
	AbductionCapture.overlayDraw = function() {
		var self = AbductionCapture; var opacity;
		var top = 0, left = 0, height = 0, width = 0;
		
		// Change colour:
		if (/^\#([a-f0-9]{3}|[a-f0-9]{6})$/i.test(self.inputs.colour.value)) {
			self.prefs.setCharPref("abduction.capture.color", self.inputs.colour.value);
			self.inputs.picker.color = self.inputs.colour.value;
		}
		
		// Change opacity:
		opacity = self.inputs.opacity.value / 100;
		self.prefs.setCharPref("abduction.capture.opacity", opacity);
		
		// Find size:
		if (self.select.height < 0) {
			height = (0 - self.select.height);
			top = self.select.top - height;
		} else {
			height = self.select.height;
			top = self.select.top;
		}
		
		if (self.select.width < 0) {
			width = (0 - self.select.width);
			left = self.select.left - width;
		} else {
			width = self.select.width;
			left = self.select.left;
		}
		
		// Set style:
		self.areas.overlay.style.background = self.inputs.picker.color;
		self.areas.overlay.style.opacity = self.areas.border.style.opacity = opacity;
		self.areas.border.style.border = "1px solid " + self.inputs.picker.color;
		
		// Set size:
		self.areas.overlay.style.top = self.areas.border.style.top = top + "px";
		self.areas.overlay.style.left = self.areas.border.style.left = left + "px";
		self.areas.overlay.style.height = self.areas.border.style.height = height + "px";
		self.areas.overlay.style.width = self.areas.border.style.width = width + "px";
	}
	
	// Start selecting:
	AbductionCapture.overlayStart = function(event) {
		var self = AbductionCapture;
		
		if (self.select.active || event.button) return;
		
		self.select.top = event.layerY;
		self.select.left = event.layerX;
		self.select.height = 1;
		self.select.width = 1;
		self.select.active = true;
		
		self.overlayDraw();
	}
	
	// Compute selection:
	AbductionCapture.overlayCompute = function(event) {
		var self = AbductionCapture;
		
		// Selection dimensions:
		self.select.height = event.layerY - self.select.top;
		self.select.width = event.layerX - self.select.left;
		
		// Square selection area:
		if (event.shiftKey) {
			var a = self.select.height, b = self.select.width, c = 0;
			
			// Both negative:
			if (a < 0 && b < 0) {
				if (a < b) b = a;
				if (b < a) a = b;
				
			// Height negative:
			} else if (a < 0) {
				a = 0 - a;
				
				if (a > b) b = a;
				if (b > a) a = b;
				
				a = 0 - a;
				
			// Width negative:
			} else if (b < 0) {
				b = 0 - b;
				
				if (a > b) b = a;
				if (b > a) a = b;
				
				b = 0 - b;
				
			// All positive:
			} else {
				if (a > b) b = a;
				if (b > a) a = b;
			}
			
			self.select.height = a;
			self.select.width = b;
		}
		
		// Prevent over selection:
		if (self.select.height + self.select.top > self.areas.canvas.height) self.select.height = self.areas.canvas.height - self.select.top;
		if (self.select.width + self.select.left > self.areas.canvas.width) self.select.width = self.areas.canvas.width - self.select.left;
		
		// Prevent under selection:
		if (self.select.height < 0 - self.select.top + 1) self.select.height = 0 - self.select.top + 1;
		if (self.select.width < 0 - self.select.left + 1) self.select.width = 0 - self.select.left + 1;
		
		// Scroll right?
		if (event.clientX + 75 > window.innerWidth) self.areas.scroll.scrollBy(25, 0);
		
		// Scroll left?
		if (event.clientX < 60) self.areas.scroll.scrollBy(-25, 0);
		
		// Scroll down?
		if (event.clientY + 110 > window.innerHeight) self.areas.scroll.scrollBy(0, 25);
		
		// Scroll left?
		if (event.clientY < 60) self.areas.scroll.scrollBy(0, -25);
		
		self.overlayDraw();
	}
	
	// Change selection:
	AbductionCapture.overlayDrag = function(event) {
		var self = AbductionCapture;
		
		if (!self.select.active || event.button) return;
		
		self.overlayCompute(event);
	}
	
	// Stop selection:
	AbductionCapture.overlayStop = function(event) {
		var self = AbductionCapture;
		
		if (!self.select.active || event.button) return;
		
		self.select.active = false;
		self.overlayCompute(event);
	}
	
	// Reset selection:
	AbductionCapture.reset = function() {
		var self = AbductionCapture;
		
		self.selecting = false;
		self.select.top = 0;
		self.select.left = 0;
		self.select.height = self.areas.canvas.height;
		self.select.width = self.areas.canvas.width;
		
		self.overlayDraw();
	}
	
	// Grab selection as canvas:
	AbductionCapture.data = function() {
		var self = AbductionCapture;
		
		// Check selection:
		if (self.select.height < 0) {
			self.select.height = (0 - self.select.height);
			self.select.top -= self.select.height;
		}
		
		if (self.select.width < 0) {
			self.select.width = (0 - self.select.width);
			self.select.left -= self.select.width;
		}
		
		// Build a temp canvas:
		var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "html:canvas");
		var context = canvas.getContext("2d");
		
		// Set the canvas size:
		canvas.height = self.select.height;
		canvas.width = self.select.width;
		
		// Copy selection:
		context.drawImage(
			self.areas.canvas, self.select.left, self.select.top,
			self.select.width, self.select.height,
			0, 0, self.select.width, self.select.height
		);
		
		return canvas;
	}
	
	// TODO: Find a way to print a canvas:
	AbductionCapture.print = function() {
		var self = AbductionCapture;
		var canvas = AbductionCapture.data();
		
		//window.print();
	}
	
	// Copy selection to clipboard:
	AbductionCapture.copy = function() {
		var self = AbductionCapture;
		var canvas = AbductionCapture.data();
		var data = canvas.toDataURL();
		var type = "image/png";
		
		var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
		
		trans.addDataFlavor(type);
		trans.setTransferData(type, data, data.length);
	}
	
	// Save selection as an image:
	AbductionCapture.save = function() {
		var self = AbductionCapture;
		var canvas = AbductionCapture.data();
		var ext = ".png", type = "image/png", data = null;
		
		// PNG High:
		if (self.inputs.format.value == 1) {
			data = canvas.toDataURL();
			
		// JPEG:
		} else {
			var quality = 100; ext = ".jpg"; type = "image/jpeg";
			
			// Medium:
			if (self.inputs.format.value == 3) quality = 70;
			
			// Low:
			if (self.inputs.format.value == 4) quality = 30;
			
			data = canvas.toDataURL(type, "quality=" + quality);
		}
		
		internalSave(data, null, self.filename + ext, null, type, true, null, null, null, false);
	}
	
/*-----------------------------------------------------------------------------------------------*/
	
	window.onload = function() {
		AbductionCapture(window.arguments[0]);
	}
	
/*-----------------------------------------------------------------------------------------------*/
